﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;

namespace NetflixMovieService
{
    /// <summary>
    /// IMovieService Interface
    /// </summary>
    public interface IMovieService
    {
        IEnumerable<ImageEntity> GetMovieBoxArtByReleaseYear(int releaseYear, int maxNumberOfResults);
    }

    /// <summary>
    /// Netflix OData Communication Service
    /// </summary>
    public class NetflixMovieService : IMovieService
    {
        // Private Constants
        private const string _ODataTitlesUrl = "http://odata.netflix.com/catalog/Titles?";
        private const string largeBoxArtBeginningTag = "<d:LargeUrl>";
        private const string largeBoxArtClosingTag = "</d:LargeUrl>";

        public IEnumerable<ImageEntity> GetMovieBoxArtByReleaseYear(int releaseYear, int maxNumberOfResults)
        {
            string xmlResults;
            if (!ValidateInput(releaseYear, maxNumberOfResults))
                return Enumerable.Empty<ImageEntity>();

            if (TryGetMovieXMLByReleaseYear(releaseYear, maxNumberOfResults, out xmlResults))
                return CreateBoxArtCollection(xmlResults);

            return Enumerable.Empty<ImageEntity>();
        }

        public IEnumerable<ImageEntity> CreateMovieEntityCollection(IEnumerable<String> movieArtCollection)
        {
            return (from x in movieArtCollection select new ImageEntity() { ImagePath = x });
        }

        private IEnumerable<ImageEntity> CreateBoxArtCollection(string xmlString)
        {
            Collection<ImageEntity> movies = new Collection<ImageEntity>();

            if (String.IsNullOrEmpty(xmlString))
                return movies;

            StringReader reader = new StringReader(xmlString);

            while (true)
            {
                string currentLine = reader.ReadLine();
                if (String.IsNullOrEmpty(currentLine))
                    break;

                string imageURL = GetImageUrl(currentLine);
                if (!String.IsNullOrEmpty(imageURL))
                    movies.Add(new ImageEntity() { ImagePath = imageURL });
            }

            return movies;
        }

        private static string GetImageUrl(string stringToParse)
        {
            stringToParse = stringToParse.Trim();

            if (stringToParse.Contains(largeBoxArtBeginningTag) && stringToParse.Contains(largeBoxArtClosingTag))
            {
                // Parse the string to get the image URL
                int startIndex = largeBoxArtBeginningTag.Length;
                int endIndex = stringToParse.Length - largeBoxArtClosingTag.Length - startIndex;
                return stringToParse.Substring(startIndex, endIndex);
            }

            return String.Empty;
        }

        private bool ValidateInput(int? releaseYear, int? maxNumberOfResults)
        {
            if (!releaseYear.HasValue || releaseYear.GetValueOrDefault() == 0)
                return false;

            if (maxNumberOfResults.HasValue && maxNumberOfResults.Value == 0)
                return false;

            return true;
        }

        private bool TryGetMovieXMLByReleaseYear(int releaseYear, int? maxNumberOfResults, out string xmlReturnString)
        {
            StringBuilder sb = new StringBuilder(_ODataTitlesUrl);

            // Set the base filter for ReleaseYear
            sb.AppendFormat("$filter=ReleaseYear eq " + releaseYear.ToString());

            // Only return the Name and BoxArt fields
            sb.AppendFormat("&$select=Name,BoxArt");

            // Set the max results
            if (maxNumberOfResults.HasValue && maxNumberOfResults.Value > 0)
                sb.AppendFormat("&$inlinecount=allpages&$top=" + maxNumberOfResults.ToString());

            // Make the request
            try
            {
                WebRequest req = WebRequest.Create(sb.ToString());
                WebResponse rsp = req.GetResponse();
                StreamReader sr = new StreamReader(rsp.GetResponseStream());
                xmlReturnString = sr.ReadToEnd();
                rsp.Close();
            }
            catch (Exception ex)
            {
                xmlReturnString = "Request failed: " + ex.Message + " with URL: " + sb;
                return false;
            }

            return true;
        }
    }
}
